home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / fscheck / fsUtils.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-10  |  30.9 KB  |  1,214 lines

  1. /* 
  2.  * fsUtils.c --
  3.  *
  4.  *    Utility procedures for fscheck
  5.  *
  6.  * Copyright 1989 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /sprite/src/cmds/fscheck/RCS/fsUtils.c,v 1.10 92/06/09 21:48:15 jhh Exp $ SPRITE (Berkeley)";
  18. #endif /* not lint */
  19.  
  20. #include "option.h"
  21. #include "list.h"
  22. #include "fscheck.h"
  23. #include <string.h>
  24. #include <host.h>
  25. #include <sys/file.h>
  26. #include <sys/stat.h>
  27. #include <stdio.h>
  28. #include <sysStats.h>
  29. #include <sys/param.h>
  30.  
  31. void WriteOutputFile();
  32. int CloseOutputFile();
  33.  
  34. FILE outputFileInfo;
  35. FILE *outputFile = &outputFileInfo;
  36.  
  37.  
  38.  
  39. /*
  40.  *----------------------------------------------------------------------
  41.  *
  42. * ReadFileDescBitmap --
  43.  *
  44.  *    Read in the file descriptor bitmap.
  45.  *
  46.  * Results:
  47.  *    A pointer to the file descriptor bit map.
  48.  *
  49.  * Side effects:
  50.  *    Memory allocated for the bit map.
  51.  *
  52.  *----------------------------------------------------------------------
  53.  */
  54. unsigned char *
  55. ReadFileDescBitmap(partFID, domainPtr)
  56.     register Ofs_DomainHeader *domainPtr;    /* Ptr to domain to read bitmap for. */
  57. {
  58.     register unsigned char *bitmap;
  59.  
  60.     /*
  61.      * Allocate the bitmap.
  62.      */
  63.     AllocByte(bitmap,unsigned char,domainPtr->fdBitmapBlocks * FS_BLOCK_SIZE);
  64.     if (tooBig) {
  65.     Output(stderr,"CheckFileSystem: Heap limit too small.\n");
  66.     exit(EXIT_MORE_MEMORY);
  67.     }
  68.     if (Disk_BlockRead(partFID, domainPtr, domainPtr->fdBitmapOffset,
  69.           domainPtr->fdBitmapBlocks, (Address)bitmap) < 0) {
  70.     OutputPerror("ReadFileDescBitmap: Read failed");
  71.     exit(EXIT_READ_FAILURE);
  72.     }
  73.     return(bitmap);
  74. }
  75.  
  76.  
  77. /*
  78.  *----------------------------------------------------------------------
  79.  *
  80.  * WriteFileDescBitmap --
  81.  *
  82.  *    Write out the file descriptor bitmap.
  83.  *
  84.  * Results:
  85.  *    None.
  86.  *
  87.  * Side effects:
  88.  *    None.
  89.  *
  90.  *----------------------------------------------------------------------
  91.  */
  92. void
  93. WriteFileDescBitmap(partFID, domainPtr, bitmap)
  94.     int                partFID;    /* Raw handle on disk. */
  95.     register Ofs_DomainHeader     *domainPtr;    /* Domain to write bitmap for.*/
  96.     register unsigned char     *bitmap;    /* Bitmap to write. */
  97. {
  98.     if (Disk_BlockWrite(partFID, domainPtr, domainPtr->fdBitmapOffset,
  99.            domainPtr->fdBitmapBlocks, (Address)bitmap) < 0) {
  100.     OutputPerror("WriteFileDescBitmap: Write failed");
  101.     exit(EXIT_WRITE_FAILURE);
  102.     }
  103. }
  104.  
  105.  
  106. /*
  107.  *----------------------------------------------------------------------
  108.  *
  109.  * ReadBitmap --
  110.  *
  111.  *    Read the bitmap off disk.
  112.  *
  113.  * Results:
  114.  *    A pointer to the bitmap.
  115.  *
  116.  * Side effects:
  117.  *    Memory allocated for the bit map.
  118.  *
  119.  *----------------------------------------------------------------------
  120.  */
  121. unsigned char *
  122. ReadBitmap(partFID, domainPtr)
  123.     int                partFID;    /* Raw disk handle. */
  124.     register Ofs_DomainHeader    *domainPtr;    /* Domain to read. */
  125. {
  126.     unsigned char *bitmap;
  127.     AllocByte(bitmap,unsigned char,domainPtr->bitmapBlocks * FS_BLOCK_SIZE);
  128.     if (tooBig) {
  129.     Output(stderr,"CheckFileSystem: Heap limit too small.\n");
  130.     exit(EXIT_MORE_MEMORY);
  131.     }
  132.     if (Disk_BlockRead(partFID, domainPtr, domainPtr->bitmapOffset,
  133.           domainPtr->bitmapBlocks, (Address) bitmap) < 0) {
  134.     OutputPerror("ReadBitmap: Read failed");
  135.     exit(EXIT_READ_FAILURE);
  136.     }
  137.     return(bitmap);
  138. }
  139.  
  140.  
  141. /*
  142.  *----------------------------------------------------------------------
  143.  *
  144.  * WriteBitmap --
  145.  *
  146.  *    Write the bitmap to disk.
  147.  *
  148.  * Results:
  149.  *    None.
  150.  *
  151.  * Side effects:
  152.  *    None.
  153.  *
  154.  *----------------------------------------------------------------------
  155.  */
  156. void
  157. WriteBitmap(partFID, domainPtr, bitmap)
  158.     int                partFID;    /* Raw handle for disk. */
  159.     register Ofs_DomainHeader    *domainPtr;    /* Domain to write. */
  160.     unsigned char        *bitmap;    /* Bitmap to write. */
  161. {
  162.     if (Disk_BlockWrite(partFID, domainPtr, domainPtr->bitmapOffset,
  163.            domainPtr->bitmapBlocks, (Address) bitmap) < 0) {
  164.     OutputPerror("WriteBitmap: Write failed");
  165.     exit(EXIT_WRITE_FAILURE);
  166.     }
  167. }
  168.  
  169.  
  170. /*
  171.  *----------------------------------------------------------------------
  172.  *
  173.  * WriteFileDesc --
  174.  *
  175.  *    Write the file descriptors to disk.
  176.  *
  177.  * Results:
  178.  *    None.
  179.  *
  180.  * Side effects:
  181.  *    File descriptors on the modified list are all written to disk.
  182.  *
  183.  *----------------------------------------------------------------------
  184.  */
  185. void
  186. WriteFileDesc(partFID, domainPtr, listPtr, descInfoPtr)
  187.     int             partFID;    /* Raw handle for disk. */
  188.     register Ofs_DomainHeader     *domainPtr;    /* Domain to write to. */
  189.     List_Links            *listPtr;    /* Pointer to list of modified
  190.                          * file descriptors to write
  191.                          * out. */
  192.     FdInfo            *descInfoPtr;    /* Pointer to info about all
  193.                          * of the descriptors. */
  194.                     
  195. {
  196.     char        block[FS_BLOCK_SIZE];
  197.     int            blockNum;
  198.     int            offset;
  199.     ModListElement    *modElemPtr;
  200.     int            badBlock;
  201.  
  202.     LIST_FORALL(listPtr, (List_Links *)modElemPtr) {
  203.     badBlock = 0;
  204.     blockNum = domainPtr->fileDescOffset + 
  205.             modElemPtr->fdNum / FSDM_FILE_DESC_PER_BLOCK;
  206.     offset = (modElemPtr->fdNum & (FSDM_FILE_DESC_PER_BLOCK - 1)) *
  207.             FSDM_MAX_FILE_DESC_SIZE;
  208.     /*
  209.      * Try to read the whole block at once unless we already know it's
  210.      * bad.  Read it a sector at a time if we hit an error earlier
  211.      * or if we get one now.
  212.      */
  213.     if ((descInfoPtr[modElemPtr->fdNum].flags &
  214.          (FD_RELOCATE|FD_UNREADABLE)) == 0) {
  215.         if (Disk_BlockRead(partFID, domainPtr, blockNum, 1,
  216.                    (Address) block) < 0) {
  217.         OutputPerror("WriteFileDesc: Warning: read failed");
  218.         badBlock = 1;
  219.         }
  220.     } else {
  221.         badBlock = 1;
  222.     }
  223.     if (badBlock) {
  224.         (void) Disk_BadBlockRead(partFID, domainPtr, blockNum,
  225.                      (Address) block);
  226.     }
  227.     bcopy((Address) modElemPtr->fdPtr, (Address) &block[offset],
  228.           sizeof(Fsdm_FileDescriptor));
  229.     if (Disk_BlockWrite(partFID, domainPtr, blockNum, 1,
  230.                (Address) block) < 0) {
  231.         OutputPerror("WriteFileDesc: Write failed");
  232.         exit(EXIT_WRITE_FAILURE);
  233.     }
  234.     }
  235. }
  236.  
  237.  
  238. /*
  239.  *----------------------------------------------------------------------
  240.  *
  241.  * WriteSummaryInfo --
  242.  *
  243.  *    Update summary information on disk.
  244.  *
  245.  * Results:
  246.  *    None.
  247.  *
  248.  * Side effects:
  249.  *    None.
  250.  *
  251.  *----------------------------------------------------------------------
  252.  */
  253. void
  254. WriteSummaryInfo(partFID, labelPtr, domainPtr, numKblocks, numFiles)
  255.     int            partFID;    /* Handle on raw disk */
  256.     Disk_Label        *labelPtr;    /* The disk label. */
  257.     Ofs_DomainHeader    *domainPtr;    /* Reference to domain header to
  258.                      * fill in */
  259.     int            numKblocks;    /* Number of 1 Kbyte blocks. */
  260.     int            numFiles;    /* Number of files. */
  261. {
  262.     Ofs_SummaryInfo    *summaryInfoPtr;
  263.     int         status;
  264.  
  265.     summaryInfoPtr = Disk_ReadSummaryInfo(partFID, labelPtr);
  266.     if (summaryInfoPtr == NULL) {
  267.     OutputPerror("WriteSummaryInfo: Read failed");
  268.     exit(EXIT_READ_FAILURE);
  269.     }
  270.     summaryInfoPtr->numFreeFileDesc = domainPtr->numFileDesc - numFiles -
  271.         numBadDesc;
  272.     summaryInfoPtr->numFreeKbytes = 
  273.         domainPtr->dataBlocks * FS_FRAGMENTS_PER_BLOCK - numKblocks;
  274.     if (clearDomainNumber) {
  275.     Output(stderr,"Clearing domain number field.\n");
  276.     summaryInfoPtr->domainNumber = -1;
  277.     }
  278.     /*
  279.      * Do not set the checked bit if there is a hard error, or if we ran
  280.      * out of memory or if the setCheckedBit flag is not set.
  281.      */
  282.     if (! (errorType < 0 || errorType == EXIT_OUT_OF_MEMORY || 
  283.        !setCheckedBit)) {
  284.     if (verbose) {
  285.         Output(stderr,
  286.         "Setting OFS_DOMAIN_JUST_CHECKED bit in summary sector.\n");
  287.     }
  288.     summaryInfoPtr->flags |= OFS_DOMAIN_JUST_CHECKED;
  289.     }
  290.     summaryInfoPtr->fixCount = fixCount;
  291.     status = Disk_WriteSummaryInfo(partFID, labelPtr, summaryInfoPtr);
  292.     if (status < 0) {
  293.     OutputPerror("WriteSummaryInfo: Write failed");
  294.     exit(EXIT_WRITE_FAILURE);
  295.     }
  296.     free((char *) summaryInfoPtr);
  297. }
  298.  
  299.  
  300. /*
  301.  *----------------------------------------------------------------------
  302.  *
  303.  * RecoveryCheck --
  304.  *
  305.  *    See if the disk was just checked. Print out information
  306.  *    from summary sector.
  307.  *
  308.  * Results:
  309.  *    Return 1 if the disk was just checked, 0 otherwise.
  310.  *
  311.  * Side effects:
  312.  *    fixCount is set to the value in the summary sector.
  313.  *
  314.  *----------------------------------------------------------------------
  315.  */
  316. int
  317. RecoveryCheck(partFID, labelPtr)
  318.     int            partFID;    /* Handle on raw disk */
  319.     Disk_Label        *labelPtr;    /* The disk label. */
  320. {
  321.     Ofs_SummaryInfo        *summaryInfoPtr;
  322.     int                i;
  323.     ReturnStatus        status = SUCCESS;
  324.     char                name[MAXHOSTNAMELEN];
  325.  
  326.     summaryInfoPtr = Disk_ReadSummaryInfo(partFID, labelPtr);
  327.     if (summaryInfoPtr == NULL) {
  328.     OutputPerror("RecoveryCheck: Summary sector read failed.\n");
  329.     exit(EXIT_READ_FAILURE);
  330.     }
  331.     fixCount = summaryInfoPtr->fixCount;
  332.     if (verbose) {
  333.     Output(stderr, "Summary Sector Info:\n");
  334.     Output(stderr, "%s domain %d %s\n", summaryInfoPtr->domainPrefix,
  335.            summaryInfoPtr->domainNumber, 
  336.            (summaryInfoPtr->flags & OFS_DOMAIN_NOT_SAFE) ? "not-safe" : 
  337.            "safe");
  338.         if (summaryInfoPtr->flags & OFS_DOMAIN_TIMES_VALID) {
  339.         Output(stderr, "Down %d seconds.\n",summaryInfoPtr->attachSeconds -
  340.            summaryInfoPtr->detachSeconds);
  341.         } else {
  342.         Output(stderr, "Attach/Detach fields not valid.\n");
  343.     }
  344.     Output(stderr, "Fscheck has fixed disk %d times already.\n", fixCount);
  345.     } else { 
  346.     Output(stderr, "\"%s\"\n", summaryInfoPtr->domainPrefix);
  347.     }
  348.     gethostname(name, MAXHOSTNAMELEN);
  349.     /*
  350.      * Check and see if the disk is already attached.  
  351.      */
  352.     for (i = 0; status == SUCCESS; i++) {
  353.     Fs_Prefix            prefix;
  354.     Host_Entry             *serverInfoPtr;
  355.  
  356.     bzero((char *) &prefix, sizeof(Fs_Prefix));
  357.     status = Sys_Stats(SYS_FS_PREFIX_STATS, i, (Address) &prefix);
  358.     if (status == SUCCESS) {
  359.         if (!strcmp(prefix.prefix, summaryInfoPtr->domainPrefix)) {
  360.         serverInfoPtr = Host_ByID(prefix.serverID);
  361.         if (serverInfoPtr == NULL) {
  362.             continue;
  363.         }
  364.         if (!strcmp(serverInfoPtr->name, name)) {
  365.             if (verbose) {
  366.             Output(stderr, "Disk is already attached\n");
  367.             }
  368.             attached = TRUE;
  369.             break;
  370.         }
  371.         }
  372.     }
  373.     }
  374.     if (clearFixCount) {
  375.     if (!silent) {
  376.         Output(stderr, "Fix count being reset to 0.\n");
  377.     }
  378.     fixCount = 0;
  379.     }
  380.     return(summaryInfoPtr->flags & OFS_DOMAIN_JUST_CHECKED);
  381. }
  382.  
  383.  
  384.  
  385. /*
  386.  *----------------------------------------------------------------------
  387.  *
  388.  * CheckFDBitmap --
  389.  *
  390.  *    Scan through the file descriptors and determine if all file 
  391.  *    descriptors marked as allocated and free in the bit map are
  392.  *    really that way.
  393.  *
  394.  * Results:
  395.  *    None.
  396.  *
  397.  * Side effects:
  398.  *    None.
  399.  *
  400.  *----------------------------------------------------------------------
  401.  */
  402.  
  403. void
  404. CheckFDBitmap(domainPtr, fdNum, block, bitmapPtrPtr)
  405.     register    Ofs_DomainHeader     *domainPtr;        /* Domain to check. */
  406.     int                 fdNum;            /* File descriptor to
  407.                              * check. */
  408.     Address             block;            /* Disk block that
  409.                              * FD is in. */
  410.     register    unsigned char      **bitmapPtrPtr;    /* Ptr to FD bitmap
  411.                              * entry for fdNum. */
  412. {
  413.     int                i, j;
  414.     register unsigned char     *bitmaskPtr;
  415.     int                   allocated;
  416.     Fsdm_FileDescriptor        *fdPtr;
  417.  
  418.     for (i = 0; 
  419.      i < FSDM_FILE_DESC_PER_BLOCK / BITS_PER_BYTE && 
  420.         fdNum < domainPtr->numFileDesc;
  421.      i++, (*bitmapPtrPtr)++){
  422.     for (j = 0, bitmaskPtr = bitmasks; 
  423.          j < BITS_PER_BYTE && fdNum < domainPtr->numFileDesc; 
  424.          j++, fdNum++, bitmaskPtr++) {
  425.  
  426.         fdPtr = (Fsdm_FileDescriptor *)&block[(i * BITS_PER_BYTE + j) * FSDM_MAX_FILE_DESC_SIZE];
  427.         allocated = **bitmapPtrPtr & *bitmaskPtr;
  428.         if (allocated && (fdPtr->flags & FSDM_FD_FREE)) {
  429.         if (bitmapVerbose) {
  430.             Output(stderr,
  431.        "Free file descriptor %d allocated in bitmap.  Bitmap corrected.\n",
  432.                    fdNum);
  433.         }
  434.         foundError = 1;
  435.         fdBitmapError = 1;
  436.         **bitmapPtrPtr &= ~*bitmaskPtr;
  437.         } else if (!allocated && !(fdPtr->flags & FSDM_FD_FREE)) {
  438.         if (bitmapVerbose) {
  439.             Output(stderr,
  440.        "Allocated file descriptor %d free in bitmap.  Bitmap corrected.\n",
  441.                    fdNum);
  442.         }
  443.         foundError = 1;
  444.         fdBitmapError = 1;
  445.         **bitmapPtrPtr |= *bitmaskPtr;
  446.         }
  447.     }
  448.     }
  449. }
  450.  
  451.  
  452. /*
  453.  *----------------------------------------------------------------------
  454.  *
  455.  * SetBadDescBitmap --
  456.  *
  457.  *    Go through the bitmaps and flag all the bits for this block as
  458.  *    allocated.
  459.  *
  460.  * Results:
  461.  *    None.
  462.  *
  463.  * Side effects:
  464.  *    None.
  465.  *
  466.  *----------------------------------------------------------------------
  467.  */
  468. void
  469. SetBadDescBitmap(domainPtr, fdNum, bitmapPtrPtr)
  470.     register    Ofs_DomainHeader     *domainPtr;        /* Domain to fix. */
  471.     int                 fdNum;            /* Bad file desc. */
  472.     register    unsigned char      **bitmapPtrPtr;    /* Ptr to bitmap entry
  473.                              * for bad file desc.*/
  474. {
  475.     int                i, j;
  476.     register unsigned char     *bitmaskPtr;
  477.  
  478.     for (i = 0; i < FSDM_FILE_DESC_PER_BLOCK / BITS_PER_BYTE && 
  479.         fdNum < domainPtr->numFileDesc;
  480.          i++, (*bitmapPtrPtr)++){
  481.     for (j = 0, bitmaskPtr = bitmasks; 
  482.          j < BITS_PER_BYTE && fdNum < domainPtr->numFileDesc; 
  483.          j++, fdNum++, bitmaskPtr++) {
  484.  
  485.          **bitmapPtrPtr |= *bitmaskPtr;
  486.      }
  487.     }
  488. }
  489.  
  490. /*
  491.  *----------------------------------------------------------------------
  492.  *
  493.  * MarkBitmap --
  494.  *
  495.  *    Mark the bits in the bit map.
  496.  *    update the cylinder map to reflect which blocks are allocated.
  497.  *
  498.  * Results:
  499.  *    -1 if couldn't mark the bitmap, 0 otherwise.
  500.  *
  501.  * Side effects:
  502.  *    None.
  503.  *
  504.  *----------------------------------------------------------------------
  505.  */
  506. int
  507. MarkBitmap(fdNum, blockNum, bitmapPtr, numFrags, domainPtr)
  508.     int          fdNum;
  509.     int          blockNum;
  510.     unsigned char *bitmapPtr;
  511.     int          numFrags;
  512.     Ofs_DomainHeader  *domainPtr;
  513. {
  514.     register    unsigned char     *bytePtr;
  515.     register    unsigned char     *bitmaskPtr;
  516.     unsigned     char              bitmask;
  517.     int                i;
  518.     int                fullBlockNum;
  519.     int                fragOffset;
  520.     int                dupBlocks;
  521.  
  522.     if (blockNum >= num1KBlocks || blockNum < 0) {
  523.     if (verbose || lastErrorFD != fdNum) {
  524.         Output(stderr, "Block pointer %d invalid in file %d\n", 
  525.                blockNum, fdNum);
  526.         lastErrorFD = fdNum;
  527.     }
  528.     foundError = 1;
  529.     return(-1);
  530.     }
  531.     bitmask = 0;
  532.     fullBlockNum = blockNum / FS_FRAGMENTS_PER_BLOCK;
  533.     bytePtr = GetBitmapPtr(domainPtr, bitmapPtr, fullBlockNum);
  534.     fragOffset = blockNum & 0x3;
  535.     if ((fullBlockNum % domainPtr->geometry.blocksPerCylinder) & 0x1) {
  536.     fragOffset += 4;
  537.     }
  538.     bitmaskPtr = &bitmasks[fragOffset];
  539.  
  540.     dupBlocks = 0;
  541.     for (i = 0; i < numFrags; i++, bitmaskPtr++) {
  542.     if (*bitmaskPtr & *bytePtr || 
  543.         (fdNum != FSDM_ROOT_FILE_NUMBER) && blockNum == 0) { 
  544.         if (noCopy) {
  545.         if (verbose || lastErrorFD != fdNum) {
  546.             Output(stderr,
  547.     "File %d references previously allocated block.  Block %d deleted.\n", 
  548.                fdNum, blockNum + i);
  549.             lastErrorFD = fdNum;
  550.         }
  551.         foundError = 1;
  552.         return -1;
  553.         }
  554.         dupBlocks++;
  555.     }
  556.     bitmask |= *bitmaskPtr;
  557.     }
  558.     if (dupBlocks > 0) {
  559.     foundError = 1;
  560.     /*
  561.      * All fragments are duplicates, so mark bitmap and return 1 so that
  562.      * these fragments are copied.
  563.      */
  564.     if (verbose || lastErrorFD != fdNum) {
  565.         Output(stderr,"File %d contains duplicate block %d.\n",fdNum,
  566.            blockNum);
  567.     }
  568.     *bytePtr |= bitmask;
  569.     return(1);
  570.     }
  571.     *bytePtr |= bitmask;
  572.     return(0);
  573. }
  574.  
  575. /*
  576.  *----------------------------------------------------------------------
  577.  *
  578.  * Output ---
  579.  *    
  580.  *    Prints the output to the given stream, and if the outputFile is  
  581.  *    not NULL it is also printed to the outputFile.
  582.  *    
  583.  * Results:
  584.  *    None.
  585.  *
  586.  * Side effects:
  587.  *    Stuff gets printed on the given stream and the output stream.
  588.  *
  589.  *----------------------------------------------------------------------
  590.  */
  591.  
  592. #ifndef lint
  593.  
  594. int
  595. Output(va_alist)
  596.     va_dcl            /* FILE *stream, then char *format, then any
  597.                  * number of additional
  598.                  * values to be printed as described by                         * format. */
  599. {
  600.     FILE *stream;
  601.     char *format;
  602.     va_list args;
  603.     static bufferFull = FALSE;
  604.     extern char *deviceName;
  605.     extern char *partName;
  606.     int    status;
  607.  
  608.     va_start(args);
  609.     stream = va_arg(args, FILE *);
  610.     format = va_arg(args, char *);
  611.     if ((!bufferFull) && (outputFile != NULL)) {
  612.     if (fprintf(outputFile, "%s%s: ", deviceName, partName) == -1) {
  613.         bufferFull = TRUE;
  614.     }
  615.     if (bufferFull != TRUE) {
  616.         if (vfprintf(outputFile, format, args) == -1) {
  617.         bufferFull = TRUE;
  618.         }
  619.     }
  620.     }
  621.     status = fprintf(stream, "%s%s: ", deviceName, partName);
  622.     if (status != -1) {
  623.     status = vfprintf(stream, format, args);
  624.     }
  625.     return status;
  626. }
  627. #else
  628. /* VARARGS1 */
  629. /* ARGSUSED */
  630. int
  631. Output(stream,format)
  632.     FILE *stream;
  633.     char *format;
  634. {
  635.     return 0;
  636. }
  637. #endif lint
  638.  
  639.  
  640. /* 
  641.  *----------------------------------------------------------------------
  642.  *
  643.  * OutputPerror --
  644.  *
  645.  *    Prints the given message on stderr and the outputFile stream 
  646.  *    using the same format as OutputPerror().
  647.  *
  648.  * Results:
  649.  *    None.
  650.  *
  651.  * Side effects:
  652.  *    Stuff gets printed.
  653.  *
  654.  *----------------------------------------------------------------------
  655.  */
  656.  
  657. #ifndef lint
  658. void
  659. OutputPerror(va_alist)
  660.     va_dcl            /* char *format, then any
  661.                  * number of additional
  662.                  * values to be printed as described by                         * format. */
  663. {
  664.     char *format;
  665.     va_list args;
  666.  
  667.     va_start(args);
  668.     format = va_arg(args, char *);
  669.     if ((format != 0) && (*format != 0)) {
  670.     Output(stderr, format, args);
  671.     }
  672.     if ((errno < 0) || (errno >= sys_nerr)) {
  673.     return;
  674.     }
  675.     Output(stderr, "%s\n", sys_errlist[errno]);
  676. }
  677.  
  678. #else
  679. /* VARARGS1 */
  680. /* ARGSUSED */
  681. void 
  682. OutputPerror(msg)
  683.     char *msg;        
  684. {
  685. }
  686. #endif
  687.  
  688.  
  689.  
  690. /*
  691.  *----------------------------------------------------------------------
  692.  *
  693.  * WriteOutputFile ---
  694.  *    
  695.  *    This procedure is invoked when the outputFile stream buffer is full.
  696.  *      All we do here is set the status on the stream to -1, to indicate
  697.  *      that the buffer is full. The buffer is actually written out when the
  698.  *    stream is closed.
  699.  *    
  700.  * Results:
  701.  *    None.
  702.  *
  703.  * Side effects:
  704.  *    Status in FILE is set to -1.
  705.  *
  706.  *----------------------------------------------------------------------
  707.  */
  708.  
  709. /*ARGSUSED*/
  710. void
  711. WriteOutputFile(stream,flush)
  712.     FILE *stream;        /* pointer to outputFile */
  713.     int flush;             /* ignore this */
  714. {
  715.     if (!silent && stream->status != -1 && 
  716.         stream->lastAccess + 1 - stream->buffer == stream->bufSize) {
  717.     fprintf(stderr,">>Output buffer overflow. %s\n",
  718.             "Subsequent output will not appear in output file.");
  719.     }
  720.     stream->status = -1;
  721. }
  722.  
  723.  
  724. /*
  725.  *----------------------------------------------------------------------
  726.  *
  727.  * CloseOutputFile ---
  728.  *
  729.  *     Flushes the buffer to disk. 
  730.  *    
  731.  * Results:
  732.  *    None.
  733.  *
  734.  * Side effects:
  735.  *    None.
  736.  *
  737.  *----------------------------------------------------------------------
  738.  */
  739.  
  740. int
  741. CloseOutputFile(stream)
  742.     FILE *stream;        /* pointer to outputFile */
  743. {
  744.     Fsdm_FileDescriptor *fdPtr;
  745.     static u_char fdBlock[FS_BLOCK_SIZE];
  746.     static u_char buffer[FS_BLOCK_SIZE];
  747.     static u_char tempBuffer[10];
  748.     int         bytesToWrite;
  749.     int            bytesWritten;
  750.     int            blockNum;
  751.     int            offset;
  752.     int            startBlock;
  753.     int            startByte;
  754.     int            i;
  755.     int            bytesUsed;
  756.     int            bytesDone;
  757.  
  758.  
  759.     if (!writeDisk) {
  760.     return;
  761.     }
  762.     if (outputFileNum == -1) {
  763.     Output(stderr,
  764.         "File %s does not exist in root directory. %s\n",
  765.         outputFileName,
  766.         "Unable to write output to disk.");
  767.         return;
  768.     }
  769.     blockNum = domainPtr->fileDescOffset + 
  770.            outputFileNum / FSDM_FILE_DESC_PER_BLOCK;
  771.     offset = (outputFileNum & (FSDM_FILE_DESC_PER_BLOCK - 1)) * 
  772.           FSDM_MAX_FILE_DESC_SIZE;
  773.     if (debug) {
  774.     Output(stderr,"Output file number is %d.\n", outputFileNum);
  775.     }
  776.     if (Disk_BlockRead(partFID, domainPtr, blockNum, 1, 
  777.                (Address) fdBlock) < 0) {
  778.     OutputPerror("Unable to read output fd.");
  779.     return;
  780.     }
  781.     fdPtr = (Fsdm_FileDescriptor *) &fdBlock[offset];
  782.     if (fdPtr->direct[0] != FSDM_NIL_INDEX) {
  783.     if (Disk_BlockRead(partFID, domainPtr,
  784.               VirtToPhys(domainPtr, fdPtr->direct[0]) /
  785.               FS_FRAGMENTS_PER_BLOCK, 1,
  786.               (Address) buffer) < 0) {
  787.         Output(stderr,"Can't read output file.");
  788.         return;
  789.     }
  790.     if (sscanf(buffer," %d",&bytesUsed) != 1) {
  791.         bytesUsed = 0;
  792.     }
  793.     } else {
  794.     bytesUsed = 0;
  795.     }
  796.     if (fdPtr->lastByte + 1 - bytesUsed  < 
  797.     stream->bufSize - stream->writeCount) {
  798.     Output(stderr,
  799.         "Output file %s is not big enough for all the output, %d > %d\n",
  800.            outputFileName, stream->bufSize - stream->writeCount, 
  801.            fdPtr->lastByte + 1 - bytesUsed);
  802.     bytesToWrite = fdPtr->lastByte + 1 - bytesUsed;
  803.     } else {
  804.     bytesToWrite = stream->bufSize - stream->writeCount;
  805.     }
  806.     if (bytesUsed + bytesToWrite > FSDM_NUM_DIRECT_BLOCKS * FS_BLOCK_SIZE) {
  807.     Output(stderr,"Output exceeds direct blocks in file.\n");
  808.     bytesToWrite = FSDM_NUM_DIRECT_BLOCKS * FS_BLOCK_SIZE - bytesUsed;
  809.     }
  810.     if (debug) {
  811.     Output(stderr,"There are %d bytes of output to be written.\n",
  812.            bytesToWrite);
  813.     }
  814.     startBlock = bytesUsed / FS_BLOCK_SIZE;
  815.     startByte = bytesUsed - startBlock * FS_BLOCK_SIZE;
  816.     bytesDone = bytesUsed;
  817.  
  818.     for (i = startBlock, bytesWritten = 0; 
  819.      bytesDone <= fdPtr->lastByte && 
  820.      i < FSDM_NUM_DIRECT_BLOCKS; 
  821.      i++) {
  822.     if (fdPtr->direct[i] == FSDM_NIL_INDEX) {
  823.         Output(stderr,"Output file has a hole -- you lose.\n");
  824.         continue;
  825.     }
  826.     if (debug) {
  827.         Output(stderr,"Writing to block %d.\n",fdPtr->direct[i]);
  828.     }
  829.     if (startByte > 0 || 
  830.         bytesToWrite - bytesWritten < FS_BLOCK_SIZE - startByte) {
  831.         int numBytes;
  832.         int bytesToZero;
  833.  
  834.         numBytes = min(bytesToWrite - bytesWritten,
  835.                FS_BLOCK_SIZE - startByte);
  836.         if (Disk_BlockRead(partFID, domainPtr,
  837.               VirtToPhys(domainPtr, fdPtr->direct[i]) /
  838.               FS_FRAGMENTS_PER_BLOCK, 1,
  839.               (Address) buffer) < 0) {
  840.         Output(stderr,"Can't read output file.");
  841.         return;
  842.         }
  843.         bcopy((Address) &stream->buffer[bytesWritten],
  844.           (Address) &buffer[startByte], numBytes);
  845.         bytesToZero = min(fdPtr->lastByte + 1 - bytesDone - numBytes,
  846.                   FS_BLOCK_SIZE - startByte - numBytes);
  847.         bzero((Address) &buffer[startByte + numBytes], bytesToZero);
  848.         if (Disk_BlockWrite(partFID, domainPtr, 
  849.                    VirtToPhys(domainPtr,fdPtr->direct[i]) / 
  850.                    FS_FRAGMENTS_PER_BLOCK, 1, buffer)  < 0) {
  851.         OutputPerror("Unable to write to output file");
  852.         return;
  853.         }
  854.         bytesWritten += numBytes;
  855.         bytesDone += numBytes + bytesToZero;
  856.         startByte = 0;
  857.     } else {
  858.         if (Disk_BlockWrite(partFID, domainPtr, 
  859.                    VirtToPhys(domainPtr,fdPtr->direct[i]) / 
  860.                    FS_FRAGMENTS_PER_BLOCK, 1, 
  861.                    (Address) &stream->buffer[bytesWritten]) < 0) {
  862.         OutputPerror("Unable to write to output file");
  863.         return;
  864.         }
  865.         bytesWritten += FS_BLOCK_SIZE;
  866.         bytesDone += FS_BLOCK_SIZE;
  867.     }
  868.     }
  869.     if (fdPtr->direct[0] != FSDM_NIL_INDEX) {
  870.     if (Disk_BlockRead(partFID, domainPtr,
  871.               VirtToPhys(domainPtr, fdPtr->direct[0]) /
  872.               FS_FRAGMENTS_PER_BLOCK, 1,
  873.               (Address) buffer) < 0) {
  874.         Output(stderr,"Can't read output file.");
  875.         return;
  876.     }
  877.     sprintf(tempBuffer,"%05d",bytesWritten + bytesUsed);
  878.     bcopy(tempBuffer, buffer, 5);
  879.     if (Disk_BlockWrite(partFID, domainPtr,
  880.               VirtToPhys(domainPtr, fdPtr->direct[0]) /
  881.               FS_FRAGMENTS_PER_BLOCK, 1,
  882.               (Address) buffer) < 0) {
  883.         Output(stderr,"Can't write output file.");
  884.         return;
  885.     }
  886.     }
  887. }
  888.  
  889.  
  890. /*
  891.  *----------------------------------------------------------------------
  892.  *
  893.  * ExitHandler ---
  894.  *
  895.  *     Called when program exits. Flushes output stream.
  896.  *    
  897.  * Results:
  898.  *    None.
  899.  *
  900.  * Side effects:
  901.  *    None.
  902.  *
  903.  *----------------------------------------------------------------------
  904.  */
  905.  
  906. void
  907. ExitHandler()
  908. {
  909.     if (outputFile != NULL && rawOutput) {
  910.     CloseOutputFile(outputFile);
  911.     }
  912. }
  913.  
  914. /*
  915.  *----------------------------------------------------------------------
  916.  *
  917.  * ClearFd ---
  918.  *
  919.  *     Clears the contents of the fd.
  920.  *    
  921.  * Results:
  922.  *    None.
  923.  *
  924.  * Side effects:
  925.  *    None.
  926.  *
  927.  *----------------------------------------------------------------------
  928.  */
  929.  
  930. void
  931. ClearFd(flags, fdPtr)
  932.     int    flags;                /* File descriptor flags */ 
  933.     Fsdm_FileDescriptor *fdPtr;        /* File descriptor to be cleared */
  934. {
  935.     int index;
  936.  
  937.     fdPtr->magic = FSDM_FD_MAGIC;
  938.     fdPtr->flags = flags;
  939.     fdPtr->firstByte = -1;
  940.     fdPtr->lastByte = -1;
  941.     fdPtr->numKbytes = 0;
  942.     fdPtr->fileType = FS_FILE;
  943.     fdPtr->uid = 0;
  944.     fdPtr->gid = 0;
  945.     fdPtr->numLinks = 0;
  946.     for (index = 0; index < FSDM_NUM_DIRECT_BLOCKS ; index++) {
  947.     fdPtr->direct[index] = FSDM_NIL_INDEX;
  948.     }
  949.     for (index = 0; index < FSDM_NUM_INDIRECT_BLOCKS ; index++) {
  950.     fdPtr->indirect[index] = FSDM_NIL_INDEX;
  951.     }
  952. }
  953.  
  954. /*
  955.  * A table indexed by a 4 bit value is used by the allocation routine to 
  956.  * quickly determine the location of 1, 2, and 3K fragments in a byte.  
  957.  * The indices of the fragments start from 0.  If there is no such fragment in 
  958.  * the byte then a -1 is used.
  959.  */
  960.  
  961. static int fragTable[16][3] = {
  962. /* 0000 */ {-1, -1, -1},
  963. /* 0001 */ {-1, -1, 0},
  964. /* 0010 */ {3, 0, -1},
  965. /* 0011 */ {-1, 0, -1},
  966. /* 0100 */ {0, 2, -1},
  967. /* 0101 */ {0, -1, -1},
  968. /* 0110 */ {0, -1, -1},
  969. /* 0111 */ {0, -1, -1},
  970. /* 1000 */ {-1, -1, 1},
  971. /* 1001 */ {-1, 1, -1},
  972. /* 1010 */ {1, -1, -1},
  973. /* 1011 */ {1, -1, -1},
  974. /* 1100 */ {-1, 2, -1},
  975. /* 1101 */ {2, -1, -1},
  976. /* 1110 */ {3, -1, -1},
  977. /* 1111 */ {-1, -1, -1}
  978. };
  979. /*
  980.  * Macros to get to the 4-bit fragment masks of the two 4K blocks that are 
  981.  * stored in a byte.
  982.  */
  983.  
  984. #define    UpperBlockFree(byte)    (((byte) & 0xf0) == 0x00)
  985. #define    LowerBlockFree(byte)    (((byte) & 0x0f) == 0x00)
  986. #define    BothBlocksFree(byte)    (((byte) & 0xff) == 0x00)
  987. #define    GetUpperFragMask(byte) (((byte) >> 4) & 0x0f)
  988. #define    GetLowerFragMask(byte) ((byte) & 0x0f)
  989.  
  990. /*
  991.  *----------------------------------------------------------------------
  992.  *
  993.  * AllocBlock --
  994.  *
  995.  *    Allocates free fragments.
  996.  *
  997.  * Results:
  998.  *    -1 if a free block cannot be found, 
  999.  *    the virtual block number of the free block otherwise
  1000.  *
  1001.  * Side effects:
  1002.  *    Marks the fragments as allocated in the bitmap
  1003.  *
  1004.  *----------------------------------------------------------------------
  1005.  */
  1006.  
  1007. int
  1008. AllocBlock(domainPtr, fragments, blockBitmapPtr)
  1009.     Ofs_DomainHeader     *domainPtr;         /* Ptr at domain info */
  1010.     int            fragments;        /* Number of fragments needed */
  1011.     u_char        *blockBitmapPtr;    /* Cylinder data block bitmap */
  1012. {
  1013.     int     mask;
  1014.     int     i;
  1015.     int        j;
  1016.     int     blocksPerCylinder;
  1017.     int        bitmapBytes;
  1018.     int     offset;
  1019.     int        fragSize;
  1020.     u_char    *bitmapPtr;
  1021.  
  1022.     if (fragments < 1 || fragments > FS_FRAGMENTS_PER_BLOCK) {
  1023.     Output(stderr,"Internal error: call to AllocBlock w/ fragments = %d\n",
  1024.            fragments);
  1025.         exit(EXIT_HARD_ERROR);
  1026.     }
  1027.     blocksPerCylinder = domainPtr->geometry.blocksPerCylinder;
  1028.     bitmapBytes = (unsigned int) (blocksPerCylinder + 1) / 2;
  1029.     mask = ((1 << fragments) - 1);
  1030.     fragSize = fragments;
  1031.  
  1032.     /*
  1033.      * Look for fragment of correct size, then size +1, size +2, etc.
  1034.      */
  1035.     while (fragSize <= FS_FRAGMENTS_PER_BLOCK) {
  1036.     for (i = 0, bitmapPtr = blockBitmapPtr; 
  1037.          i < domainPtr->dataCylinders; 
  1038.          i++) {
  1039.  
  1040.         for (j = 0; j < bitmapBytes; j++, bitmapPtr++) {
  1041.         /*
  1042.          * Block 0 belongs to the root directory so don't allocate it 
  1043.          * even if it is free.
  1044.          */
  1045.         if (j + i != 0) {
  1046.             if (fragSize == 4) {
  1047.             if (UpperBlockFree(*bitmapPtr)) {
  1048.                 mask <<= FS_FRAGMENTS_PER_BLOCK - fragments;
  1049.                 *bitmapPtr |= mask << 4;
  1050.                 return (i * blocksPerCylinder + j * 2) * 
  1051.                     FS_FRAGMENTS_PER_BLOCK; 
  1052.             }
  1053.             } else {
  1054.             offset = 
  1055.                 fragTable[GetUpperFragMask(*bitmapPtr)][fragSize-1];
  1056.             if (offset > -1) {
  1057.                 mask <<= FS_FRAGMENTS_PER_BLOCK - offset - 
  1058.                      fragments;
  1059.                 *bitmapPtr |= mask << 4;
  1060.                 return (i * blocksPerCylinder + j * 2) * 
  1061.                     FS_FRAGMENTS_PER_BLOCK + offset; 
  1062.             }
  1063.             }
  1064.         }
  1065.         /*
  1066.          * There may be an odd number of blocks per cylinder.  If so
  1067.          * and are at the end of the bit map for this cylinder, then
  1068.          * we can bail out now.
  1069.          */
  1070.     
  1071.         if (j == (bitmapBytes - 1) && (blocksPerCylinder & 0x1)) {
  1072.             continue;
  1073.         }
  1074.         if (fragSize == 4) {
  1075.             if (LowerBlockFree(*bitmapPtr)) {
  1076.             mask <<= FS_FRAGMENTS_PER_BLOCK - fragments;
  1077.             *bitmapPtr |= mask;
  1078.             return (i * blocksPerCylinder + j * 2 + 1) * 
  1079.                 FS_FRAGMENTS_PER_BLOCK; 
  1080.             }
  1081.         } else {
  1082.             offset = 
  1083.             fragTable[GetLowerFragMask(*bitmapPtr)][fragSize-1];
  1084.             if (offset > -1) {
  1085.             mask <<= FS_FRAGMENTS_PER_BLOCK - offset - fragments;
  1086.             *bitmapPtr |= mask;
  1087.             return (i * blocksPerCylinder + j * 2 + 1) * 
  1088.                 FS_FRAGMENTS_PER_BLOCK + offset; 
  1089.             }
  1090.         }
  1091.         }
  1092.     }
  1093.     fragSize++;
  1094.     }
  1095.     /*
  1096.      * Disk is full
  1097.      */
  1098.     return -1;
  1099. }
  1100.  
  1101.  
  1102. /*
  1103.  *----------------------------------------------------------------------
  1104.  *
  1105.  * AddToCopyList --
  1106.  *
  1107.  *    Adds information about the block to be copied to the copy list.
  1108.  *
  1109.  * Results:
  1110.  *    None.
  1111.  *
  1112.  * Side effects:
  1113.  *    Copy list element is malloced, added to copy list.
  1114.  *
  1115.  *----------------------------------------------------------------------
  1116.  */
  1117.  
  1118. void
  1119. AddToCopyList(parentType,fdPtr, fdNum, blockNum, index, blockType,fragments,
  1120.           copyUsedPtr)
  1121.     ParentType        parentType;     /* either a fd or an indirect block */
  1122.     Fsdm_FileDescriptor    *fdPtr;        /* ptr to parent fd */
  1123.     int            fdNum;        /* number of parent fd */
  1124.     int            blockNum;    /* number of parent block */
  1125.     int            index;        /* index of pointer  in parent */
  1126.     BlockIndexType    blockType;    /* type of block being copied */
  1127.     int            fragments;    /* number of fragments to copy*/
  1128.     Boolean        *copyUsedPtr;    /* Was copy of fd used ? */
  1129. {
  1130.     CopyListElement    *copyPtr;
  1131.  
  1132.     Alloc(copyPtr,CopyListElement,1);
  1133.     if (!tooBig) {
  1134.     List_InitElement((List_Links *) copyPtr);
  1135.     copyPtr->fdPtr = fdPtr;
  1136.     copyPtr->parentType = parentType;
  1137.     if (parentType == FD) {
  1138.         copyPtr->parentNum = fdNum;
  1139.         *copyUsedPtr = TRUE;
  1140.     } else {
  1141.         copyPtr->parentNum = blockNum;
  1142.     }
  1143.     copyPtr->index = index;
  1144.     copyPtr->blockType = blockType;
  1145.     copyPtr->fragments = fragments;
  1146.     List_Insert((List_Links *) copyPtr,
  1147.             LIST_ATREAR(copyList));
  1148.     }
  1149. }
  1150.  
  1151.  
  1152. /*
  1153.  *----------------------------------------------------------------------
  1154.  *
  1155.  * FindOutputFile --
  1156.  *
  1157.  *    Finds the output file for raw output.  This routine should only
  1158.  *    be called if the disk has been checked previously, since the
  1159.  *    output file will be found in CheckDirTree otherwise.
  1160.  *    
  1161.  *
  1162.  * Results:
  1163.  *    None.
  1164.  *
  1165.  * Side effects:
  1166.  *    None.
  1167.  *
  1168.  *----------------------------------------------------------------------
  1169.  */
  1170.  
  1171. void
  1172. FindOutputFile()
  1173. {
  1174.     Fsdm_FileDescriptor    *rootFDPtr;
  1175.     FdInfo        fdInfo;
  1176.     DirIndexInfo    dirIndex;
  1177.     Fslcl_DirEntry    *dirEntryPtr;
  1178.     int            length;
  1179.     int            blockNum;
  1180.     int            offset;
  1181.     static char        block[FS_BLOCK_SIZE];
  1182.     extern void        OpenDir();
  1183.     extern void        NextDirEntry();
  1184.  
  1185.  
  1186.     if (!rawOutput) {
  1187.     return;
  1188.     }
  1189.     if (outputFileName == NULL) {
  1190.     return;
  1191.     }
  1192.     length = strlen(outputFileName);
  1193.     blockNum = domainPtr->fileDescOffset + 
  1194.             FSDM_ROOT_FILE_NUMBER / FSDM_FILE_DESC_PER_BLOCK;
  1195.     offset = (FSDM_ROOT_FILE_NUMBER & (FSDM_FILE_DESC_PER_BLOCK - 1)) * 
  1196.         FSDM_MAX_FILE_DESC_SIZE;
  1197.     if (Disk_BlockRead(partFID, domainPtr, blockNum, 1, 
  1198.                (Address) block) < 0) {
  1199.        return;
  1200.     }
  1201.     rootFDPtr = (Fsdm_FileDescriptor *) &block[offset];
  1202.     OpenDir(rootFDPtr, &fdInfo, &dirIndex, &dirEntryPtr);
  1203.     while (dirEntryPtr != (Fslcl_DirEntry *) NULL) {
  1204.     if ((dirEntryPtr->nameLength == length) &&
  1205.         (strncmp(outputFileName, dirEntryPtr->fileName, length) == 0)) {
  1206.  
  1207.         outputFileNum = dirEntryPtr->fileNumber;
  1208.         return;
  1209.     }
  1210.     NextDirEntry(&dirIndex, &dirEntryPtr);
  1211.     }
  1212. }
  1213.  
  1214.